#pragma once
#include"meta_stream.hpp"
using namespace meta_ios;

using protocols::only_stream_from_unref;
using protocols::only_stream_cache_unref;

// Transfer all characters from input stream up to '#' into output stream
template<class ty_list>
using fetch_before_hashtag = meta_all_transfer<meta_ostream<exp_list<>>,
    meta_istream<ty_list>, only_stream_cache_unref<value_is<'#'>>>;

// Ensure the text ends with '\0', append if not present
template<class text>
using zero_end_fix = typename meta_invoke<
    invoke_if<!value_equal<typename to_exp_list_t<text>::back, '\0'>>,
    meta_ostream<text>, exp_char<'\0'>>::type;

// Print function: replaces '#' in the string with arguments, recursively
template<class m_str, class std_ostream, class First, class...Rest>
void print_impl(m_str str, std_ostream& os, First const& first, const Rest&...rest) {
    // Extract text before first '#' and the rest of the string
    using hash_tag_read_stream = fetch_before_hashtag<
        typename m_str::template to<exp_list>
    >;
    using current_text = typename hash_tag_read_stream::to::type;
    using rest_text = meta_fold<
        meta_invoke<typename hash_tag_read_stream::from>,
        get_type, 
        to_exp_char_t
    >;

    // Output the current text and the first argument
    os << to_exp_char_t<zero_end_fix<current_text>>{} << first;
    // Recursively process the rest of the arguments and string
    if constexpr (sizeof...(Rest)) {
        ::print_impl(rest_text{}, os, rest...);
    }
    else {
        // Output the remaining text if no more arguments
        os << rest_text{};
    }
}

template<exp_utilities::static_str str, class std_ostream, class ...argts>
void print(std_ostream& os, argts const& ...args) {
    print_impl(str_to_list<str>{}, os, args...);
}
